Bài 15. Stack

Liên hệ QC

befaint

|||||||||||||
Tham gia
6/1/11
Bài viết
14,369
Được thích
19,330
Bài 15. Stack

(Danh sách các bài viết về VBA xem ở đây Index - Các bài viết về VBA)

Stack là một thư viện nằm trong “System.Collections” của .NET Framework. Cho phép lưu trữ dữ liệu (items) có kích cỡ lớn, rất hữu ích trong các tình huống khi cần xử lý trước nhất những items mà truyền vào Stack sau cùng.
Yêu cầu: Hệ thống phải cài đặt .NET Framework.

1. Khai báo Stack
1.1. Kiểu khai báo sớm
(Không có Tooltip khi gọi Stack, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “mscorlib.dll” trong cửa sổ References – VBAProject.
Khai báo trong code:
PHP:
Dim oStack As New Stack

1.2. Kiểu khai báo muộn
(Không có Tooltip khi gọi Stack, không cần thiết lập trong Tools/References).
Khai báo trong code:
PHP:
Dim oStack As Object
Set oStack = CreateObject("System.Collections.Stack")

2. Các phương thức, thuộc tính
2.1. Push
PHP:
oStack.Push Item
Thêm một Item vào vị trí trên cùng (top) của Stack.
Item nhận kiểu dữ liệu bất kỳ (kiểu số hoặc chuỗi), giá trị đơn hoặc array.
Ví dụ:
PHP:
Sub PushMethod()
    'Dim oStack As New Stack'
    Dim oStack As Object
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Push Item'
    oStack.Push 5
    oStack.Push "TextA"
    oStack.Push ""
End Sub

2.2. Count
PHP:
oStack.Count
Trả về số Items có trong Stack.
Ví dụ:
PHP:
Sub CountProperty()
    Dim oStack As Object
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Count'
    oStack.Push 5
    oStack.Push "TextA"
    MsgBox oStack.Count '2'
End Sub

2.3. Peek
PHP:
oStack.Peek
Trả về Item trên cùng của Stack và không xóa Item đó.
Ví dụ:
PHP:
Sub PeekMethod()
    Dim oStack As Object, i As Long
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Peek'
    For i = 1 To 10
        oStack.Push "Value-" & i
    Next i
    MsgBox oStack.Peek  'Value-10'
End Sub

2.4. Pop
PHP:
oStack.Pop
Xóa và trả về Item trên cùng của Stack.
Ví dụ:
PHP:
Sub PopMethod()
    Dim oStack As Object, i As Long, sValue As String
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Pop'
    For i = 1 To 10
        oStack.Push "Value-" & i
    Next i
    sValue = oStack.Pop
    MsgBox sValue       'Value-10'
    MsgBox oStack.Count '9'
End Sub

2.5. Contains
PHP:
oStack.Contains
Kiểm tra sự tồn tại của một Item trong Stack. Trả về True nếu Item đó tồn tại, ngược lại trả về False.
Ví dụ:
PHP:
Sub ContainsMethod()
    Dim oStack As Object
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Contains'
    oStack.Push 5
    oStack.Push "TextA"
    MsgBox oStack.Contains(5)       'True'
    MsgBox oStack.Contains("TextA") 'True'
    MsgBox oStack.Contains("TextB") 'False
End Sub

2.6. ToArray
PHP:
oStack.ToArray
Sao chép các Items trong Stack vào một mảng (Array). Mảng trả về là mảng một chiều, chỉ số cận dưới của mảng luôn bằng 0, cho dù thiết lập Option Base 1.
Ví dụ:
PHP:
Sub ToArrayMethod()
    Dim oStack As Object, i As Long, arr()
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.ToArray     Mang 1 chieu,cac phan tu trong mang xep nguoc, khong phu thuoc Option Base 1'
    For i = 1 To 10
        oStack.Push i
    Next i
    arr = oStack.ToArray
    MsgBox arr(0)   '10'
End Sub

2.7. Clear
PHP:
oStack.Clear
Xóa tất cả các Items có trong Stack.
Ví dụ:
PHP:
Sub ClearMethod()
    Dim oStack As Object, i As Long
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Clear'
    For i = 1 To 10
        oStack.Push i
    Next i
    oStack.Clear
    MsgBox oStack.Count '0'
End Sub

2.8. Clone
PHP:
oStack.Clone
Sao chép toàn bộ Stack đã dựng sang một Stack mới.
Ví dụ:
PHP:
Sub CloneMethod()
    Dim oStack As Object, newStack As Object
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.Clone'
    oStack.push 20
    Set newStack = oStack.Clone
    MsgBox newStack.Peek    '20'
End Sub

2.9. ToString
PHP:
oStack.ToString
Trả về tên đối tượng hiện hành, tức là “System.Collections.Stack”.
Ví dụ:
PHP:
Sub ToStringMethod()
    Dim oStack As Object, sName As String
    Set oStack = CreateObject("System.Collections.Stack")
    'oStack.ToString'
    sName = oStack.ToString
    MsgBox sName    'System.Collections.Stack'
End Sub

2.10. GetHashCode
PHP:
oStack.GetHashCode
'(…)'

 

File đính kèm

  • Stack.xlsb
    28.3 KB · Đọc: 46
Lần chỉnh sửa cuối:
3. Ứng dụng
- Lọc loại trùng
- …
3.1. Hàm lọc loại trùng trong một cột
PHP:
'// Loc loai trung mot cot'
Public Function UniqueColumnStack(ByVal Rng As Range) As Variant
    If Rng.Count = 1 Then UniqueColumnStack = Rng.Value: Exit Function
    Dim HTbl As Object, i As Long, j As Long, arr(), Result(), sKey As Variant
    Set HTbl = CreateObject("System.Collections.Stack")
    arr = Rng.Value
    For i = LBound(arr, 1) To UBound(arr, 1)
        sKey = arr(i, 1)
        If sKey <> "" Then
            If HTbl.Containskey(sKey) = False Then
                HTbl.Add sKey, ""
                j = j + 1
                ReDim Preserve Result(1 To j)
                Result(j) = sKey
            End If
        End If
    Next i
    UniqueColumnStack = Result
End Function

3.2. Hàm truyền các Items của Stack sang mảng 2 chiều
PHP:
'// Truyen cac Items cua Stack sang mang 2 chieu'
Public Function StackToArray2D(oStack As Object, Optional ByVal Reverse As Boolean = False) As Variant
    Dim iCount As Long
    iCount = oStack.Count
    If iCount = 0 Then Exit Function
    Dim Result(), i As Long, j As Long, arr()
    ReDim Result(1 To iCount, 1 To 1)
    arr = oStack.ToArray
    If Reverse = False Then
        For i = LBound(arr) To UBound(arr) Step 1
            j = j + 1
            Result(j, 1) = arr(i)
        Next i
    Else
        For i = UBound(arr) To LBound(arr) Step -1
            j = j + 1
            Result(j, 1) = arr(i)
        Next i
    End If
    StackToArray2D = Result
End Function

3.3. Ví dụ so sánh tốc độ Add Keys với kiểu dữ liệu là kiểu số
Stack:
PHP:
Sub AddKeys_Stack()
    Dim TT As Double
    TT = Timer
    Dim oStack As Object
    Set oStack = CreateObject("System.Collections.Stack")
    Dim x As Long, y As Long, i As Long
    x = 1000000000
    y = 1000020000
    For i = x To y
        If oStack.Contains(i) = False Then
            oStack.push i
        End If
    Next i
    Set oStack = Nothing
    MsgBox Round(Timer - TT, 2) '1.64-1.78 giây'
End Sub
Hashtable:
PHP:
Sub AddKeys_Hashtable()
    Dim TT As Double
    TT = Timer
    Dim HTbl As Object
    Set HTbl = CreateObject("System.Collections.Hashtable")
    Dim x As Long, y As Long, i As Long
    x = 1000000000
    y = 1000020000
    For i = x To y
        If HTbl.Containskey(i) = False Then
            HTbl.Add i, ""
        End If
    Next i
    Set HTbl = Nothing
    MsgBox Round(Timer - TT, 2) '0.19-0.20 giây'
End Sub
Dictionary:
PHP:
Sub AddKeys_Dictionary()
    Dim TT As Double
    TT = Timer
    Dim Dic As Object
    Set Dic = CreateObject("Scripting.Dictionary")
    Dim x As Long, y As Long, i As Long
    x = 1000000000
    y = 1000020000
    For i = x To y
        If Dic.Exists(i) = False Then
            Dic.Add i, ""
        End If
    Next i
    Set Dic = Nothing
    MsgBox Round(Timer - TT, 2) '5.96-6.09 giây'
End Sub
 
Upvote 0
Trừ phi bạn đưa ra được trường hợp điển hình để sử dụng loại cấu trúc này, tôi e rằng bạn đi hơi sâu vào .Net và vượt xa mục đích thực tiễn của VBA.

Khong phải là stack không có công dụng. Nhưng đối với Excel thì rất ít. Cái lợi biết thêm 1 chút kiến thức không đủ bù cái công học.

Tuy nói thế, tôi vẫn mạn phép thêm một ít giải thích để các bạn dễ hình dung ra cái cấu trúc này:

Stack tiếng Việt là ngăn xếp (*). Đây là loại cấu trúc dữ liệu dựng ra để thực hiện tính chất LIFO (Last In First Out - Vào Sau Ra Trước). Để dễ hiểu, có thể hình dung như một chồng sách:
1. Mỗi lần đặt thêm một quyển sách, quyển mới này là quyển trên cùng (hành động được diễn tả bằng Push trong bài #1)
2. Nếu cần lấy ra một quyển sách thì bắt buộc chỉ có quyển trên cùng là lấy ra được. (Pop trong bài #1)
- Ví dụ bạn muốn đạt đến quyển thứ ba, bạn khong thể nắm nó mà rút ngang. Cách duy nhất (không còn cách nào khác) là Pop ra quyển trên cùng, Pop quyển kế đó rồi mới chạm được quyển thứ ba. Tức là phải Pop 2 lần mới lòi ra quyển thứ ba trở thành trên cùng, lúc đó muốn lấy nó thì Pop thêm lần nữa. Lưu ý là mỗi lần lấy ra một quyển thì coi như quyển ấy không còn nằm trong chồng.
3. Bạn có thể lật quyển trên cùng, và chỉ quyển trên cùng mà thôi, ra xem mà không cần phải lấy nó ra. (Peek trong bài #1)
4. Bạn có thể đếm xem trong chồng có bao nhiêu quyển sách. (Count trong bài #1)
Các tính chất kể từ 5 trở đi không phải là tính chất thuần tuý của stack. Chúng được thêm vào để cải thiện sử dụng tuỳ theo system hoặc platform, vv...
5. Bạn có thể dùng tựa bìa để xét xem một quyển nào đó có trong chồng (nếu là chồng sách thật thì bạn duyệt qua gáy sách). (Contains trong bài #1)
6. Bạn có thể liệng bỏ cả chồng để lấy chỗ lập chồng khác (Clear trong bài #1)
Các tính chất kể từ 7 trở đi là do thừa kế từ lớp Collection của .Net
7. Bạn có thể đóng cả chồng sách lại thành một bộ (ToArray trong bài #1)
Các tính chất kể từ 8 trở đi là kế thừa từ các lớp căn bản khác của .Net
8. Bạn có thể copy cả chồng (Clone)
9. Bạn có thể đổi kiểu chúng thành chuỗi. (ToString)
- Đây là tính chất thừa kế từ lớp căn bản nhất (Object), và mỗi lớp có cách hoạt động khác nhau.
Tính chất thứ 10 sau đây thuộc về cao cấp, .Net không bảo đảm là nó luôn luôn lúc nào cũng như nhau (mỗi phiên bản có thể dùng một giải thuật khác)
10. Bạn có thể xem qua kết quả của key sau khi băm (GetHashCode)
Còn vài tính chất nữa không được nói tới trong bài #1, miễn giải thích.

(*) tôi cũng chưa rõ tại sao các nhà khoa học ta lại chọn dịch như vậy. Có lẽ do nếu dùng từ "chồng" sẽ dễ nhầm với Heap, một từ khác trong kỹ thuật lập trình.
(**) tôi dùng ví dụ chồng sách cho dễ hình dung. Thực ra, chồng sách hàm ý chúng đồng loại với nhau, và điều này không đúng. Stack có thể chứa nhiều loại khác nhau, nhưng vẫn phải theo nguyên tắc cái sau chồng trên cái trước.
 
Upvote 0
Trừ phi bạn đưa ra được trường hợp điển hình để sử dụng loại cấu trúc này, tôi e rằng bạn đi hơi sâu vào .Net và vượt xa mục đích thực tiễn của VBA.

Khong phải là stack không có công dụng. Nhưng đối với Excel thì rất ít. Cái lợi biết thêm 1 chút kiến thức không đủ bù cái công học.

Tuy nói thế, tôi vẫn mạn phép thêm một ít giải thích để các bạn dễ hình dung ra cái cấu trúc này:

Stack tiếng Việt là ngăn xếp (*). Đây là loại cấu trúc dữ liệu dựng ra để thực hiện tính chất LIFO (Last In First Out - Vào Sau Ra Trước). Để dễ hiểu, có thể hình dung như một chồng sách:
1. Mỗi lần đặt thêm một quyển sách, quyển mới này là quyển trên cùng (hành động được diễn tả bằng Push trong bài #1)
2. Nếu cần lấy ra một quyển sách thì bắt buộc chỉ có quyển trên cùng là lấy ra được. (Pop trong bài #1)
- Ví dụ bạn muốn đạt đến quyển thứ ba, bạn khong thể nắm nó mà rút ngang. Cách duy nhất (không còn cách nào khác) là Pop ra quyển trên cùng, Pop quyển kế đó rồi mới chạm được quyển thứ ba. Tức là phải Pop 2 lần mới lòi ra quyển thứ ba trở thành trên cùng, lúc đó muốn lấy nó thì Pop thêm lần nữa. Lưu ý là mỗi lần lấy ra một quyển thì coi như quyển ấy không còn nằm trong chồng.
3. Bạn có thể lật quyển trên cùng, và chỉ quyển trên cùng mà thôi, ra xem mà không cần phải lấy nó ra. (Peek trong bài #1)
4. Bạn có thể đếm xem trong chồng có bao nhiêu quyển sách. (Count trong bài #1)
Các tính chất kể từ 5 trở đi không phải là tính chất thuần tuý của stack. Chúng được thêm vào để cải thiện sử dụng tuỳ theo system hoặc platform, vv...
5. Bạn có thể dùng tựa bìa để xét xem một quyển nào đó có trong chồng (nếu là chồng sách thật thì bạn duyệt qua gáy sách). (Contains trong bài #1)
6. Bạn có thể liệng bỏ cả chồng để lấy chỗ lập chồng khác (Clear trong bài #1)
Các tính chất kể từ 7 trở đi là do thừa kế từ lớp Collection của .Net
7. Bạn có thể đóng cả chồng sách lại thành một bộ (ToArray trong bài #1)
Các tính chất kể từ 8 trở đi là kế thừa từ các lớp căn bản khác của .Net
8. Bạn có thể copy cả chồng (Clone)
9. Bạn có thể đổi kiểu chúng thành chuỗi. (ToString)
- Đây là tính chất thừa kế từ lớp căn bản nhất (Object), và mỗi lớp có cách hoạt động khác nhau.
Tính chất thứ 10 sau đây thuộc về cao cấp, .Net không bảo đảm là nó luôn luôn lúc nào cũng như nhau (mỗi phiên bản có thể dùng một giải thuật khác)
10. Bạn có thể xem qua kết quả của key sau khi băm (GetHashCode)
Còn vài tính chất nữa không được nói tới trong bài #1, miễn giải thích.

(*) tôi cũng chưa rõ tại sao các nhà khoa học ta lại chọn dịch như vậy. Có lẽ do nếu dùng từ "chồng" sẽ dễ nhầm với Heap, một từ khác trong kỹ thuật lập trình.
(**) tôi dùng ví dụ chồng sách cho dễ hình dung. Thực ra, chồng sách hàm ý chúng đồng loại với nhau, và điều này không đúng. Stack có thể chứa nhiều loại khác nhau, nhưng vẫn phải theo nguyên tắc cái sau chồng trên cái trước.
Có bài này của anh là em yên tâm rồi, vì lúc soạn bài trên em cũng không nắm hết được.

Cảm ơn anh.
 
Upvote 0
Trừ phi bạn đưa ra được trường hợp điển hình để sử dụng loại cấu trúc này, tôi e rằng bạn đi hơi sâu vào .Net và vượt xa mục đích thực tiễn của VBA.
Với mình, nếu viết code trên VBA thì Dictionary, Collection là quá đủ. Thêm nữa có thể là ArrayList
Chỉ cần biết một món Dictionary thì mấy món kia có thể tự suy luận (bởi cách dùng là gần tượng tự)
Điều quan trọng mà tác giả chưa đề cập đó là:
- Điều gì tạo nên sự khác biệt giữa Arraylist, Dictionary hay Stack.... ?
- Có trường hợp nào mà tôi dùng cái này thì sẽ tối ưu hơn cái kia không?

Ví dụ: Dictionary và ArrayList đều có khả năng lọc duy nhất, nhưng tôi sẽ dùng ArrayList thay cho Dictionary khi tôi cần thêm công đoạn sort mảng chẳng hạn
 
Upvote 0
Với mình, nếu viết code trên VBA thì Dictionary, Collection là quá đủ. Thêm nữa có thể là ArrayList
Chỉ cần biết một món Dictionary thì mấy món kia có thể tự suy luận (bởi cách dùng là gần tượng tự)
Điều quan trọng mà tác giả chưa đề cập đó là:
- Điều gì tạo nên sự khác biệt giữa Arraylist, Dictionary hay Stack.... ?
- Có trường hợp nào mà tôi dùng cái này thì sẽ tối ưu hơn cái kia khong6?

Nói đến Stack là nói đến LIFO và 3P's : Push, Pop, Peek
Theo tôi biết thì Stack hầu như không có công dụng thực tiễn nào trong Excel.
Cái công dụng mà tôi có thể nghĩ ra được là dùng để
1. đảo nghịch chuỗi liên kết
2. ghi lại các trạng thái thay đổi của mọt biến hay cái gì đó và undo nếu cần
Rất tiếc là kể từ hồi vào GPE đến giờ, tôi chưa hề thấy đề bài nào cần đến 1 trong 2 công việc trên.
Cũng như ý bạn, tôi nghĩ là với VBA, Dictionary, Collection và ArrayList là quá đủ. Học thêm Stack thì cái lợi không đủ bù cái công.

Việc so sánh ứng dụng các đối tượng trên khá phức tạp. Cần phải có nhiều nghiên cứu. Và bài viết bảo đảm là sẽ có nhiều tranh cãi. Vấn đề là ở đây các thành viên đã có đủ cái mức độ chững chạc để tranh cãi không thành kiến, không để tình cảm và tự ái cá nhân chen vào?

Chú: lý thuyết stack có thể dùng để thiết kế hàm đệ quy, và để debug ở kỹ thuật cao - nhưng đó là lý thuyết, chứ khong phải là áp dụng cái class Stack của .Net
 
Upvote 0
Web KT
Back
Top Bottom